package model;

import domain.City;
import domain.Student;
import domain.Country;
import domain.Sex;
import util.HibernateUtil;
import java.util.Date;
import java.util.List;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import util.ErroLogging;
import web.ServletUtilMethods;

public class ModelImpl implements Model {

    Session session;
    private static final int ALL_ROWS_NEEDED = -100;

    public ModelImpl() {
        this.session = HibernateUtil.getSessionFactory().getCurrentSession();
    }

    @Override
    public Country getCountry(int id) throws EltcException {
        Country obj = null;
        try {
            Transaction tx = session.beginTransaction();
            Query q = session.createQuery("from Country as c where c.id = '" + id + "'");
            obj = (Country) q.uniqueResult();

        } catch (Exception e) {
            throw new EltcException(e.getMessage());
        }
        return obj;
    }

    @Override
    public void addCountry(Country bean) throws EltcException {
        if (isExistsCountry(bean)) {
            throw new EltcException("Объект " + bean + " уже существует");
        }

        Transaction tx = null;
        try {
            session = HibernateUtil.getSessionFactory().getCurrentSession();
            tx = session.beginTransaction();
            session.save(bean);
            tx.commit();
        } catch (HibernateException ex) {
            ErroLogging.prinStackMessage(ex);
            throw new EltcException(ex.getMessage());
        }
    }

    @Override
    public void addCountries(Country[] array) throws EltcException {
        Transaction tx = null;
        try {
            session = HibernateUtil.getSessionFactory().getCurrentSession();
            tx = session.beginTransaction();
            for (Country country : array) {
                session.save(country);
            }
            tx.commit();
        } catch (HibernateException ex) {
            ErroLogging.prinStackMessage(ex);
            throw new EltcException(ex.getMessage());
        }
    }

    @Override
    public void modifiedCountry(Country obj) throws EltcException {
        if (obj == null) {
            throw new EltcException("Объект на инициализирован");
        }
        if (obj.getId() == 0) {
            throw new EltcException("Код на задан");
        }
        if (obj.getName() == null || obj.getName().isEmpty()) {
            throw new EltcException("Наименование на задано");
        }

        // Country country = null;
        try {
            Transaction tx = session.beginTransaction();
            //Query q = session.createQuery("from Country as c where c.name = '" + obj.getName() + "'");
            //country = (Country) q.uniqueResult();
            session.update(obj);
            tx.commit();
        } catch (Exception e) {
            ErroLogging.prinStackMessage(e);
            throw new EltcException(e.getMessage());
        }
    }

    @Override
    public Country[] findCountry(Country obj) throws EltcException {
        if (obj == null) {
            throw new EltcException("Объект на инициализирован");
        }
        if (obj.getName() == null || obj.getName().isEmpty()) {
            throw new EltcException("Наименование на задано");
        }
        List<Country> cList = null;
        try {
            org.hibernate.Transaction tx = session.beginTransaction();
            Query q = session.createQuery("from Country as с where с.name like '%" + obj.getName() + "%'");
            cList = (List<Country>) q.list();

        } catch (Exception e) {
            ErroLogging.prinStackMessage(e);
            throw new EltcException("Проблемы при получении стран", e);
        }
        return cList.toArray(new Country[0]);
    }

    @Override
    public Country[] getCountries() throws EltcException {
        return getCountriesFromTo(ALL_ROWS_NEEDED, 0);
    }

    @Override
    public boolean isExistsCountry(Country obj) throws EltcException {
        if (obj == null) {
            throw new EltcException("Объект на инициализирован");
        }
        if (obj.getName() == null || obj.getName().isEmpty()) {
            throw new EltcException("Наименование на задано");
        }
        Country country = null;
        try {
            Transaction tx = session.beginTransaction();
            Query q = session.createQuery("from Country as c where c.name = '" + obj.getName() + "'");
            country = (Country) q.uniqueResult();
        } catch (Exception e) {
            throw new EltcException(e.getMessage());
        }
        return country != null;
    }

    @Override
    public Country[] getCountriesFromTo(int start, int end) throws EltcException {
        List<Country> cList = null;

        int startReal = start - 1; // because we want to have records from 1 to 20 (include 1), HQL
        // wants to see 0 to 20 (0 not included)
        try {
            org.hibernate.Transaction tx = session.beginTransaction();
            //Query q = session.createQuery("from Film as film where film.filmId between '" + startID + "' and '" + endID + "'");
            Query q = session.createQuery("from Country");
            // In case it's mean all records necessary
            if (start != ALL_ROWS_NEEDED) {
                q.setFirstResult(startReal);
                q.setMaxResults(end);
            }
            cList = (List<Country>) q.list();

        } catch (Exception e) {
            ErroLogging.prinStackMessage(e);
            throw new EltcException("Проблмы при получении стран", e);
        }
        return cList.toArray(new Country[0]);
    }

    @Override
    public int getCountriesSize() throws EltcException {
        org.hibernate.Transaction tx = session.beginTransaction();
        int count = ((Long) session.createQuery("select count(*) from Country").uniqueResult()).intValue();
        return count;
    }

    public <T> T getObject(int id, Class cl) throws EltcException {
        String className = cl.getSimpleName();
        T obj = null;
        try {
            session = HibernateUtil.getSessionFactory().getCurrentSession();
            Transaction tx = session.beginTransaction();
            Query q = session.createQuery("from " + className + " as c where c.id = '" + id + "'");
            obj = (T) q.uniqueResult();
        } catch (Exception e) {
            throw new EltcException(e.getMessage());
        }
        return obj;
    }

    public <T> List<T> getObjectsFromTo(int start, int end, Class cl) throws EltcException {
        List<T> cList = null;

        int startReal = start - 1; // because we want to have records from 1 to 20 (include 1), HQL
        // wants to see 0 to 20 (0 not included)
        try {
            session = HibernateUtil.getSessionFactory().getCurrentSession();
            org.hibernate.Transaction tx = session.beginTransaction();
            //Query q = session.createQuery("from Film as film where film.filmId between '" + startID + "' and '" + endID + "'");
            Query q = session.createQuery("from " + cl.getSimpleName());
            // In case it's mean all records necessary
            if (start != ALL_ROWS_NEEDED) {
                q.setFirstResult(startReal);
                q.setMaxResults(end);
            }
            cList = (List<T>) q.list();

        } catch (Exception e) {
            ErroLogging.prinStackMessage(e);
            throw new EltcException("Проблмы при получении стран", e);
        }
        return cList;
    }

    public <T> List<T> getObjectsFromToList(int start, int end, Class cl) throws EltcException {
        List<T> cList = null;

        int startReal = start - 1; // because we want to have records from 1 to 20 (include 1), HQL
        // wants to see 0 to 20 (0 not included)
        try {
            session = HibernateUtil.getSessionFactory().getCurrentSession();
            org.hibernate.Transaction tx = session.beginTransaction();
            //Query q = session.createQuery("from Film as film where film.filmId between '" + startID + "' and '" + endID + "'");
            Query q = session.createQuery("from " + cl.getSimpleName());
            // In case it's mean all records necessary
            if (start != ALL_ROWS_NEEDED) {
                q.setFirstResult(startReal);
                q.setMaxResults(end);
            }
            cList = (List<T>) q.list();

        } catch (Exception e) {
            ErroLogging.prinStackMessage(e);
            throw new EltcException("Проблемы при получении справочника " + cl.getName(), e);
        }
        return cList;
    }

    public <T> List<T> getObjects(Class cl) throws EltcException {
        List<T> list = getObjectsFromTo(ALL_ROWS_NEEDED, 0, cl);
        return list;
    }
    //    public City getCity(int id) throws EltcException {
//        throw new UnsupportedOperationException("Not supported yet.");
//    }
//
//    public void addCity(City obj) throws EltcException {
//        throw new UnsupportedOperationException("Not supported yet.");
//    }
//
//    public void modifiedCity(City obj) throws EltcException {
//        throw new UnsupportedOperationException("Not supported yet.");
//    }
//
//    public City[] findCity(City obj) throws EltcException {
//        throw new UnsupportedOperationException("Not supported yet.");
//    }
//
//    public City[] getCities() throws EltcException {
//        throw new UnsupportedOperationException("Not supported yet.");
//    }
//
//    public City[] getCitiesFromTo(int start, int end) throws EltcException {
//        throw new UnsupportedOperationException("Not supported yet.");
//    }
//
//    public boolean isExistsCity(Country obj) throws EltcException {
//        throw new UnsupportedOperationException("Not supported yet.");
//    }
//
//    public int getCitiesSize() throws EltcException {
//        throw new UnsupportedOperationException("Not supported yet.");
//    }
//
//
//
//    public Student getStudent(int id) throws EltcException {
//        domain.Student obj = null;
//        try {
//            Transaction tx = session.beginTransaction();
//            Query q = session.createQuery("from Student as c where c.id = '" + id + "'");
//            obj = (domain.Student) q.uniqueResult();
//        } catch (Exception e) {
//            throw new EltcException(e.getMessage());
//        }
//        return obj;
//    }
//
//    public void addStudent(Student obj) throws EltcException {
//        Transaction tx = null;
//        try {
//            session = HibernateUtil.getSessionFactory().getCurrentSession();
//            tx = session.beginTransaction();
//            session.save(obj);
//            tx.commit();
//        } catch (HibernateException ex) {
//            ErroLogging.prinStackMessage(ex);
//            throw new EltcException(ex.getMessage());
//        }
//    }
//
//    public void modifiedStudent(Student obj) throws EltcException {
//        // Country country = null;
//        try {
//            Transaction tx = session.beginTransaction();
//            //Query q = session.createQuery("from Country as c where c.name = '" + obj.getName() + "'");
//            //country = (Country) q.uniqueResult();
//            session.update(obj);
//            tx.commit();
//        } catch (Exception e) {
//            ErroLogging.prinStackMessage(e);
//            throw new EltcException(e.getMessage());
//        }
//    }
//
//    public Student[] findStudent(Student obj) throws EltcException {
//        throw new UnsupportedOperationException("Not supported yet.");
//    }
//
//    public Student[] getStudents() throws EltcException {
//        throw new UnsupportedOperationException("Not supported yet.");
//    }
//
//    public Student[] getStudentsFromTo(int start, int end) throws EltcException {
//        throw new UnsupportedOperationException("Not supported yet.");
//    }
//
//    public boolean isExistsStudent(Student obj) throws EltcException {
//        throw new UnsupportedOperationException("Not supported yet.");
//    }
//
//    public int getStudentsSize() throws EltcException {
//        throw new UnsupportedOperationException("Not supported yet.");
//    }
//
//    public void addStudent(model.StudentOld obj) throws EltcException {
//        throw new UnsupportedOperationException("Not supported yet.");
//    }
//
//    public void modifiedStudent(model.StudentOld obj) throws EltcException {
//        throw new UnsupportedOperationException("Not supported yet.");
//    }
//
//    public boolean isExistsStudent(model.StudentOld obj) throws EltcException {
//        throw new UnsupportedOperationException("Not supported yet.");
//    }
//
//    public Sex getSex(char sexChar) throws EltcException {
//        if (sexChar != 'm' && sexChar != 'f') {
//            throw new EltcException("arg must be  'm' or 'f'");
//        }
//        session = HibernateUtil.getSessionFactory().getCurrentSession();
//        int id = sexChar == 'm' ? 1 : 2;
//        Sex obj = null;
//        try {
//            Transaction tx = session.beginTransaction();
//            Query q = session.createQuery("from Sex as c where c.id = '" + id + "'");
//            obj = (Sex) q.uniqueResult();
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//
//        return obj;
//    }

    public <T> void addObject(T bean) throws EltcException {
        Transaction tx = null;
        try {
            session = HibernateUtil.getSessionFactory().getCurrentSession();
            tx = session.beginTransaction();
            session.save(bean);
            tx.commit();
        } catch (HibernateException ex) {
            ErroLogging.prinStackMessage(ex);
            throw new EltcException(ex.getMessage());
        }
    }

    public <T> void modifyObject(T obj) throws EltcException {
        if (obj == null) {
            throw new EltcException("Объект на инициализирован");
        }
        try {
            session = HibernateUtil.getSessionFactory().getCurrentSession();
            Transaction tx = session.beginTransaction();
            session.update(obj);
            tx.commit();
        } catch (Exception e) {
            ErroLogging.prinStackMessage(e);
            throw new EltcException(e.getMessage());
        }
    }

    public <T> void removeObject(T obj) throws EltcException {
         if (obj == null) {
            throw new EltcException("Объект на инициализирован");
        }
        try {
            session = HibernateUtil.getSessionFactory().getCurrentSession();
            Transaction tx = session.beginTransaction();
            session.delete(obj);
            tx.commit();
        } catch (Exception e) {
            ErroLogging.prinStackMessage(e);
            throw new EltcException(e.getMessage());
        }
    }
}
